package com.black.template.excelToPdf;

import com.itextpdf.text.Font;
import com.itextpdf.text.*;
import com.itextpdf.text.pdf.PdfPCell;
import com.itextpdf.text.pdf.PdfPTable;
import org.apache.poi.hssf.usermodel.HSSFFont;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.hssf.util.HSSFColor;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.xssf.usermodel.XSSFColor;
import org.apache.poi.xssf.usermodel.XSSFFont;
import java.io.IOException;
import java.net.MalformedURLException;
import java.util.ArrayList;
import java.util.List;

/**
 * Created by cary on 6/15/17.
 */
public class PdfTableExcel {
    protected ExcelObject excelObject;
    protected Excel excel;
    protected boolean setting = false;

    /**
     * <p>Description: Constructor</p>
     *
     * @param excelObject
     */
    public PdfTableExcel(ExcelObject excelObject) {
        this.excelObject = excelObject;
        this.excel = excelObject.getExcel();
    }

    /**
     * <p>Description: 获取转换过的Excel内容Table</p>
     *
     * @return PdfPTable
     * @throws BadElementException
     * @throws MalformedURLException
     * @throws IOException
     */
    public PdfPTable getTable() throws BadElementException, MalformedURLException, IOException {
        Sheet sheet = this.excel.getSheet();
        return toParseContent(sheet);
    }

//    private PdfPCell createPdfPCell(int colIndex, int rowIndex, Cell cell) {
//
//    }

    protected PdfPTable toParseContent(Sheet sheet) throws BadElementException, MalformedURLException, IOException {
        //行
        int rows = sheet.getPhysicalNumberOfRows();
        List<PdfPCell> cells = new ArrayList<>();
        float[] widths = null;
        float mw = 0;
        for (int i = 0; i < rows; i++) {
            Row row = sheet.getRow(i);
            if (row == null) {
                continue;
            }
            //列
            int columns = row.getLastCellNum();
            if (columns<0&&i==rows-1){
                continue;
            }
            //单元格宽度数组
            float[] cws = new float[columns];
            for (int j = 0; j < columns; j++) {
                Cell cell = row.getCell(j);
                if (cell == null) {
                    cell = row.createCell(j);
                }
                //单元格宽度
                float cw = getPOIColumnWidth(cell);
                cws[cell.getColumnIndex()] = cw;
                //pdf单元格
                PdfPCell pdfpCell = new PdfPCell();
                pdfpCell.setVerticalAlignment(getVAlignByExcel(cell.getCellStyle().getVerticalAlignment().getCode()));
                pdfpCell.setHorizontalAlignment(getHAlignByExcel(cell.getCellStyle().getAlignment().getCode()));
                if (sheet.getDefaultRowHeightInPoints() != row.getHeightInPoints()) {
                    pdfpCell.setFixedHeight(row.getHeightInPoints());
                }
                pdfpCell.setPhrase(getPhrase(cell));
                addImageByPOICell(pdfpCell, cell);
                addBorderByExcel(pdfpCell, cell.getCellStyle());
                //pdf单元格背景色等样式
                if (cell.getCellStyle().getFillForegroundColorColor() == null){
                    pdfpCell.setBackgroundColor(BaseColor.WHITE);
                }else{
                    Color fillForegroundColorColor = cell.getCellStyle().getFillForegroundColorColor();
                    int rgb = POIUtil.getRGB(fillForegroundColorColor);
                    if (rgb==0x00FFFFFF){
                        pdfpCell.setBackgroundColor(BaseColor.WHITE);
                    }else{
                        BaseColor baseColor = new BaseColor(rgb);
                        pdfpCell.setBackgroundColor(baseColor);
                    }
                }
                CellRangeAddress range = getColSpanRowSpanByExcel(row.getRowNum(), cell.getColumnIndex());
                int rowSpan = 1;
                int colSpan = 1;
                int rowIndex = cell.getRowIndex();
                int columnIndex = cell.getColumnIndex();
                if (range != null) {
                    rowSpan = range.getLastRow() - range.getFirstRow() + 1;
                    colSpan = range.getLastColumn() - range.getFirstColumn() + 1;
                }
                pdfpCell.setColspan(colSpan);
                pdfpCell.setRowspan(rowSpan);
                if (range !=null){
                    cells.add(pdfpCell);
                    j += colSpan - 1;
                }else{
                    int num = sheet.getNumMergedRegions();
                    boolean flag = true;
                    for (int m = 0; m < num; m++) {
                        CellRangeAddress mergedRegion = sheet.getMergedRegion(m);
                       if(mergedRegion.isInRange(rowIndex,columnIndex)){
                            flag = false;
                            break;
                        }
                    }
                    if (flag){
                        cells.add(pdfpCell);
                    }
                }
            }
            float rw = 0;
            for (float cw : cws) {
                rw += cw;
            }
            if (rw > mw || mw == 0) {
                widths = cws;
                mw = rw;
            }
        }
        PdfPTable table = new PdfPTable(widths);
        table.setWidthPercentage(100);
        for (PdfPCell pdfpCell : cells) {
            table.addCell(pdfpCell);
        }
        return table;
    }


    protected Phrase getPhrase(Cell cell) {
        if (this.setting || this.excelObject.getAnchorName() == null) {
            Font font = getFontByExcel(cell,true);
            String value = String.valueOf(getCellValue(cell));
            Phrase elements = new Phrase(value, font);
            if (font.isUnderlined()){
                elements = new Phrase();
                Font font1 = getFontByExcel(cell,false);
                Chunk chunk = new Chunk(value,font1);
                chunk.setUnderline(1.0f,-2.0f);
                elements.add(chunk);
            }
            return elements;
        }
        Anchor anchor = new Anchor(String.valueOf(getCellValue(cell)), getFontByExcel(cell,true));
        anchor.setName(this.excelObject.getAnchorName());
        this.setting = true;
        return anchor;
    }


    /**
     * 获取单元格值
     * @return 单元格值
     */
    public Object getCellValue(Cell cell) {
        Object val = "";
        try {
            if (cell != null) {
                if (cell.getCellType() == CellType.NUMERIC) {
                    val = cell.getNumericCellValue();
                    if (DateUtil.isCellDateFormatted(cell)) {
                        // POI Excel 日期格式转换
                        val = DateUtil.getJavaDate((Double) val);
                    } else {
//                        if ((Double) val % 1 > 0) {
//                            val = new DecimalFormat("0.00").format(val);
//                        } else {
//                            val = new DecimalFormat("0").format(val);
//                        }
                    }
                }
                else if (cell.getCellType() == CellType.FORMULA){
                    System.out.println(cell.getStringCellValue());
                    val = cell.getCellFormula();
                    System.out.println(val);
                }
                else if (cell.getCellType() == CellType.STRING) {
                    val = cell.getStringCellValue();
                } else if (cell.getCellType() == CellType.BOOLEAN) {
                    val = cell.getBooleanCellValue();
                } else if (cell.getCellType() == CellType.ERROR) {
                    val = cell.getErrorCellValue();
                }
            }
        } catch (Exception e) {
            return val;
        }
        return val;
    }


    protected void addImageByPOICell(PdfPCell pdfpCell, Cell cell) throws BadElementException, MalformedURLException, IOException {
        POIImage poiImage = new POIImage().getCellImage(cell);
        byte[] bytes = poiImage.getBytes();
        if (bytes != null) {
            Image image = Image.getInstance(bytes);
            pdfpCell.setCellEvent(new ImageBackgroundEvent(image));
        }
    }

    /**
     * <p>Description: 此处获取Excel的列宽像素(无法精确实现,期待有能力的朋友进行改善此处)</p>
     * @param cell
     * @return 像素宽
     */
    protected int getPOIColumnWidth(Cell cell) {
        // com.itextpdf.text.pdf.PdfPTable.calculateWidths,此方法已经等比例转换了。不知道为什么还需要转换
        // int colWidthpoi = poiCWidth;
        // int widthPixel = 0;
        // if (colWidthpoi >= 416) {
        //     widthPixel = (int) (((colWidthpoi - 416.0) / 256.0) * 8.0 + 13.0 + 0.5);
        // } else {
        //     widthPixel = (int) (colWidthpoi / 416.0 * 13.0 + 0.5);
        // }
        //System.out.println("poiCWidth: "+poiCWidth/256);
        return excel.getSheet().getColumnWidth(cell.getColumnIndex());
    }

    protected CellRangeAddress getColSpanRowSpanByExcel(int rowIndex, int colIndex) {
        CellRangeAddress result = null;
        Sheet sheet = excel.getSheet();
        int num = sheet.getNumMergedRegions();
        for (int i = 0; i < num; i++) {
            CellRangeAddress range = sheet.getMergedRegion(i);
            if (range.getFirstColumn() == colIndex && range.getFirstRow() == rowIndex) {
                result = range;
            }
        }
        return result;
    }

    protected Font getFontByExcel(Cell cell,boolean withUnderline) {
        CellStyle style = cell.getCellStyle();
        Font result = new Font(Resource.BASE_FONT_CHINESE, 8, Font.NORMAL);
        Workbook wb = excel.getWorkbook();
        int index = style.getFontIndexAsInt();
        org.apache.poi.ss.usermodel.Font font = wb.getFontAt(index);
        Integer rbg = null ;
        float fontHeightInPoints = 0;
        if (font instanceof HSSFFont) {
            HSSFFont hssfFont = (HSSFFont) font;
            HSSFColor color = hssfFont.getHSSFColor((HSSFWorkbook)wb);
            if(color!=null){
                rbg = POIUtil.getRGB(color);
            }
            fontHeightInPoints = hssfFont.getFontHeightInPoints();
            Font font1 = Resource.getFont(hssfFont);
            if (font1!=null){
                result = font1;
            }else{
                result.setSize(fontHeightInPoints);
            }
        }
        else if (font instanceof XSSFFont) {
            XSSFFont xssfFont = (XSSFFont) font;
            XSSFColor color = xssfFont.getXSSFColor();
            if(color!=null){
                rbg = POIUtil.getRGB(color);
            }
            Font font1 = Resource.getFont(xssfFont);
            fontHeightInPoints = xssfFont.getFontHeightInPoints();
            if (font1!=null){
                result = font1;
            }else{
                result.setSize(fontHeightInPoints);
            }
        }
        if (rbg != null) {
            result.setColor(new BaseColor(rbg));
        }
        FontUnderline underline = FontUnderline.valueOf(font.getUnderline());
        int fontStyle = Font.NORMAL;
        if (underline == FontUnderline.SINGLE) {
            if (withUnderline){
                fontStyle = fontStyle| Font.UNDERLINE;
            }
        }
        if (font.getBold()){
            fontStyle = fontStyle|Font.BOLD;
        }
        if (font.getItalic()){
            fontStyle = fontStyle| Font.ITALIC;
        }
        result.setStyle(fontStyle);
        return result;
    }

    protected void addBorderByExcel(PdfPCell cell, CellStyle style) {
        Workbook wb = excel.getWorkbook();
        int border = Rectangle.NO_BORDER;
        if (!BorderStyle.NONE.equals(style.getBorderBottom())){
            border = border|Rectangle.BOTTOM;
            cell.setBorderColorBottom(new BaseColor(POIUtil.getBorderRBG(wb, style.getBottomBorderColor())));
        }
        if (!BorderStyle.NONE.equals(style.getBorderLeft())){
            border = border|Rectangle.LEFT;
            cell.setBorderColorLeft(new BaseColor(POIUtil.getBorderRBG(wb, style.getLeftBorderColor())));
        }
        if (!BorderStyle.NONE.equals(style.getBorderRight())){
            border = border|Rectangle.RIGHT;
            cell.setBorderColorRight(new BaseColor(POIUtil.getBorderRBG(wb, style.getRightBorderColor())));
        }
        if (!BorderStyle.NONE.equals(style.getBorderTop())){
            border = border|Rectangle.TOP;
            cell.setBorderColorTop(new BaseColor(POIUtil.getBorderRBG(wb, style.getTopBorderColor())));
        }
        cell.setBorder(border);
    }

    protected int getVAlignByExcel(short align) {
        int result = 0;
        if (align == VerticalAlignment.BOTTOM.getCode()) {
            result = Element.ALIGN_BOTTOM;
        }
        if (align == VerticalAlignment.CENTER.getCode()) {
            result = Element.ALIGN_MIDDLE;
        }
        if (align == VerticalAlignment.JUSTIFY.getCode()) {
            result = Element.ALIGN_JUSTIFIED;
        }
        if (align == VerticalAlignment.TOP.getCode()) {
            result = Element.ALIGN_TOP;
        }
        return result;
    }

    protected int getHAlignByExcel(short align) {
        int result = 0;
        if (align == HorizontalAlignment.RIGHT.getCode()) {
            result = Element.ALIGN_RIGHT;
        }
        if (align == HorizontalAlignment.JUSTIFY.getCode()) {
            result = Element.ALIGN_JUSTIFIED;
        }
        if (align == HorizontalAlignment.CENTER.getCode()) {
            result = Element.ALIGN_CENTER;
        }
        return result;
    }
}